Skip to content

chore(tao): migrate decorated-window-tao to Compose 1.12.0-rc01 - #354

Merged
kdroidFilter merged 1 commit into
nucleus-2.5from
chore/compose-1.12-beta02-tao
Aug 16, 2026
Merged

chore(tao): migrate decorated-window-tao to Compose 1.12.0-rc01#354
kdroidFilter merged 1 commit into
nucleus-2.5from
chore/compose-1.12-beta02-tao

Conversation

@kdroidFilter

@kdroidFilter kdroidFilter commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Why

Get ahead of the Compose 1.12 release: the no-AWT decorated-window-tao
backend drives Compose's internal androidx.compose.ui.scene.* APIs directly,
so it's the one module that breaks on a minor Compose bump.

Rebased on current main (the previous head conflicted after the Tao
JetBrains-style refactor). Bumped from 1.12.0-beta02 to 1.12.0-rc01
(latest published RC — 1.12.0 stable is still not out). Catalog flip to
stable later is one line.

What changed in the 1.12 ComposeScene API

  • ComposeScene.render(canvas, nanoTime) removed → three steps:
    FrameRecomposer.performFrame(nanoTime) + ComposeScene.measureAndLayout() +
    ComposeScene.draw(canvas).
  • Scene factories (Canvas/PlatformLayersComposeScene) drop coroutineContext
    • invalidate; now take a FrameRecomposer (which owns the frame clock) +
      invalidateLayout / invalidateDraw. The manual per-host BroadcastFrameClock
      and frameClock.sendFrame() calls are gone.
  • ComposeSceneContext.createLayer: compositionContextconsumePointerInputOutside.
  • ComposeSceneLayer.setContent(parentCompositionContext, content) + new abstract
    consumePointerInputOutside property.
  • LocalSystemTheme is now internal and typed as Skiko SystemTheme.
    ProvideNucleusSystemTheme still feeds Nucleus's live dark-mode detector into
    that local (INVISIBLE_REFERENCE, same pattern as other Compose-internal
    bridges).

Approach

Scene create/render/dispose plumbing is centralized in TaoSceneBundle
(scene/TaoSceneBundle.kt). Each host/popup/overlay stores a TaoSceneBundle?
and keeps val scene get() = sceneBundle?.scene, so the ~20 scene?.… call
sites per file are untouched — only create/render/close move. Future Compose
bumps touch one file for the shared logic.

Behaviour is kept at parity with the 1.11 path: the paced frameNs is still fed
to the frame clock for standalone popups, and every invalidation
(invalidateLayout/invalidateDraw + the recomposer's own) funnels into the
same coalescing frame scheduler that invalidate used before.

The offscreen scene test harness (TaoSceneTestHarness) moves onto the same
bundle: recordSceneToPictureFrameRecomposer.performFrame, which flushes
its own dispatchers around the tick.

Note: SingleComposeSceneRenderingScope

Compose Desktop's AWT path wraps the three render calls in
SingleComposeSceneRenderingScope.render, but that method is Kotlin-internal
(JVM-public, module-private) and invisible to external backends. TaoSceneBundle
inlines performFramemeasureAndLayoutdraw directly. The only thing
lost vs. upstream is its isRendering-guarded invalidation de-dup — which the
old Tao code didn't have either, and the FrameDispatcher coalescing covers it.

Catalog

was (main) this PR
Compose 1.11.1 1.12.0-rc01
Material3 1.9.0 1.12.0-alpha03 (Expressive APIs public)
Compose Hot Reload 1.1.1 1.2.0 (bundled by the 1.12 RC plugin)
AGP 8.13.2 9.1.1

Fallout: AGP 9 / Java 17

Compose 1.12 also pulls AndroidX Compose 1.12 into examples:cmp-demo's Android
target, which requires AGP ≥ 9.1 and compileSdk 37. That cascades:

  • agp 8.13.2 → 9.1.1 (9.2+ needs Gradle ≥ 9.4.1, we're on 9.4.0), cmp-demo
    compileSdk/targetSdk 35 → 37.
  • android.builtInKotlin=false + android.newDsl=false: since AGP 9,
    com.android.application is rejected alongside the KMP plugin, which points at
    com.android.kotlin.multiplatform.library — a library plugin, unusable for
    cmp-demo (a KMP module that builds a real Android app) without splitting it into
    a separate :androidApp module. These are AGP's documented escape hatches.
  • plugin-build/plugin jvmTarget 11 → 17 — AGP 9 artifacts are built for 17
    and can't be resolved by an 11-targeted consumer. User-visible: the Nucleus
    Gradle plugin now needs a Gradle daemon on JVM 17+ (mandatory since Gradle 9
    anyway; Gradle 8 + JVM 11 setups are no longer supported).
  • Dropped a stray org.jetbrains.skia.Surface import from cmp-demo's
    commonMain — unused, and unresolvable on Android.

Verification

  • :decorated-window-tao:compileKotlin + compileTestKotlin — clean on this
    rebase (macOS / JDK 21).
  • :nucleus-application:compileKotlin, :examples:compose-demo:compileKotlin,
    :examples:extra-launcher-demo:compileKotlin.
  • Headful macOS smoke with the Material 3 Expressive sample (issue Compose animation causes higher memory usage #541
    LoadingIndicator 300.dp + wavy indicators): Tao window comes up on 1.12 RC
    and paints. Whole-process phys_footprint (Activity Monitor Memory) idle →
    animating is 170 → 284 MB on Tao vs 247 → 353 MB on vanilla Compose
    Desktop. The jump is Metal GPU cache (Owned physical footprint (unmapped) (graphics)), not a 1.12/Tao regression.

Not re-run on this rebase: the full :decorated-window-tao:check suite from
the original PR (78 tests), plugin-build :plugin:check, assembleDebug for
cmp-demo, or native smoke on Windows / Linux.

Before merge

  • Switch catalog compose line to 1.12.0 stable when it ships
  • Re-run :decorated-window-tao:check and plugin-build checks after CI
  • Run the native standalone-popup smoke tests on the three OSes
  • Confirm the plugin's JVM 17 floor is acceptable as a released change

@kdroidFilter
kdroidFilter force-pushed the chore/compose-1.12-beta02-tao branch 2 times, most recently from 3799541 to 1bcd42f Compare July 26, 2026 12:14
kdroidFilter added a commit that referenced this pull request Aug 16, 2026
Rebased PR #354 on main and bumped Compose from 1.12.0-beta02 to the
latest RC. Scene create/render/dispose lives in TaoSceneBundle so the
1.12 FrameRecomposer + measureAndLayout + draw split is in one place.
Material3 moves to 1.12.0-alpha03 (Expressive APIs) and hot-reload to
1.2.0 to match the RC plugin bundle.
@kdroidFilter
kdroidFilter force-pushed the chore/compose-1.12-beta02-tao branch from 1bcd42f to 130570f Compare August 16, 2026 08:57
@kdroidFilter kdroidFilter changed the title chore(tao): migrate decorated-window-tao to Compose 1.12.0-beta02 chore(tao): migrate decorated-window-tao to Compose 1.12.0-rc01 Aug 16, 2026
@kdroidFilter
kdroidFilter marked this pull request as ready for review August 16, 2026 11:50
Rebased PR #354 on main and bumped Compose from 1.12.0-beta02 to the
latest RC. Scene create/render/dispose lives in TaoSceneBundle so the
1.12 FrameRecomposer + measureAndLayout + draw split is in one place.
Material3 moves to 1.12.0-alpha03 (Expressive APIs) and hot-reload to
1.2.0 to match the RC plugin bundle.
@kdroidFilter
kdroidFilter force-pushed the chore/compose-1.12-beta02-tao branch from 130570f to 5d5cfc4 Compare August 16, 2026 11:53
@kdroidFilter
kdroidFilter changed the base branch from main to nucleus-2.5 August 16, 2026 11:53
@kdroidFilter

Copy link
Copy Markdown
Collaborator Author

Retargeted from main (2.4.x) to nucleus-2.5.

nucleus-2.5 now includes #536 (spellcheck). This branch was rebased onto that tip so the PR only contains the Compose 1.12 commits. :decorated-window-tao, :nucleus-application (including spellcheck UI), :decorated-window-jewel, :examples:jewel-demo, and :examples:tao-demo compile clean against 1.12.0-rc01 on this rebase.

@kdroidFilter
kdroidFilter merged commit 4f4049b into nucleus-2.5 Aug 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant